﻿using System;
using System.Diagnostics;
using FluentNHibernate;
using FluentNHibernate.Automapping;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Conventions;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;

namespace Scribble.Repositories
{
    public class NHibernateConfigurator
    {
        public ISessionFactory GetSessionFactory()
        {
            return Fluently.Configure()
                .Database(ConfigureDatabase)
                .Mappings(CreateMappings)
                .ExposeConfiguration(BuildSchema)
                .ExposeConfiguration(WriteToTrace)
                .BuildSessionFactory();
        }

        private void WriteToTrace(Configuration configuration)
        {
            configuration.SetInterceptor(new SqlStatementInterceptor());
        }

        private IPersistenceConfigurer ConfigureDatabase()
        {
            return MsSqlConfiguration.MsSql2008
                .ConnectionString(c => c.FromConnectionStringWithKey("ScribbleData"));
        }

        private void CreateMappings(MappingConfiguration mappingConfiguration)
        {
            mappingConfiguration.AutoMappings.Add(
                AutoMap
                    .AssemblyOf<Entity>(new FluentConfiguration())
                    .Conventions.Add<CustomeForeignKeyConvention>()
                );
        }

        private void BuildSchema(Configuration configuration)
        {
            new SchemaExport(configuration).Create(true, false);
        }

        private class SqlStatementInterceptor : EmptyInterceptor
        {
            public override NHibernate.SqlCommand.SqlString OnPrepareStatement(NHibernate.SqlCommand.SqlString sql)
            {
                Trace.WriteLine(sql.ToString());
                return sql;
            }
        }

        private class CustomeForeignKeyConvention : ForeignKeyConvention
        {
            protected override string GetKeyName(Member property, Type type)
            {
                return (property == null ? type.Name : property.Name) + "Id";
            }
        }
    }
}